<?php

namespace support;

use app\exception\ValidateException;
use think\Validate;

/**
 * 基础请求验证类
 * 统一处理验证逻辑和错误抛出
 */
abstract class BaseRequest
{
    /**
     * 输入数据
     * @var array
     */
    protected $input = [];

    /**
     * 验证后的数据
     * @var array
     */
    protected $validatedData = [];

    /**
     * 是否已验证
     * @var bool
     */
    protected $isValidated = false;

    public function __construct(array $input = [])
    {
        $this->input = $input;
    }

    /**
     * 定义验证规则
     *
     * @return array
     */
    public function rules(): array
    {
        $rule_action = 'getRulesBy' . ucfirst($this->getActionMethod());
        if (method_exists($this, $rule_action)) {
            return $this->$rule_action();
        }
        return $this->getDefaultRules();
    }

    /**
     * 获取当前 action 方法名（需外部 set 或传入）
     */
    protected function getActionMethod(): string
    {
        // 默认返回 'Json'，可在 new 时传入或 set
        return $this->input['_action'] ?? '';
    }

    /**
     * 获取默认验证规则
     *
     * @return array
     */
    protected function getDefaultRules(): array
    {
        return [];
    }

    /**
     * 获取验证错误消息
     *
     * @return array
     */
    public function messages(): array
    {
        return [
            // 子类可以重写此方法添加自定义错误消息
        ];
    }

    /**
     * 获取验证属性名称
     *
     * @return array
     */
    public function attributes(): array
    {
        return [
            // 子类可以重写此方法添加属性名称映射
        ];
    }

    /**
     * 执行验证并返回验证后的数据
     *
     * @return array
     * @throws \Exception
     */
    public function validated(): array
    {
        if (!$this->isValidated) {
            $this->validate();
        }
        return $this->validatedData;
    }

    /**
     * 执行验证
     *
     * @throws \Exception
     */
    protected function validate(): void
    {
        try {
            $rules = $this->rules();
            $input = $this->input;
            $validate = new Validate();
            $validate->rule($rules);
            $messages = $this->messages();
            if (!empty($messages)) {
                $validate->message($messages);
            }
            if (!$validate->check($input)) {
                throw new \Exception($validate->getError());
            }
            $this->validatedData = $input;
            $this->isValidated = true;
        } catch (\Exception $e) {
            $this->handleValidationError($e);
        }
    }

    /**
     * 统一处理验证错误
     *
     * @param \Exception $e
     * @throws \Exception
     */
    protected function handleValidationError(\Exception $e): void
    {
        $errorMessage = $this->formatErrorMessage($e);
        throw new ValidateException($errorMessage, 422);
    }

    /**
     * 格式化错误消息
     *
     * @param \Exception $e
     * @return string
     */
    protected function formatErrorMessage(\Exception $e): string
    {
        $errorMessage = $e->getMessage();
        if (preg_match('/^(.+?):\s*(.+)$/', $errorMessage, $matches)) {
            $fieldName = trim($matches[1]);
            $ruleMessage = trim($matches[2]);
            $attributes = $this->attributes();
            $displayName = $attributes[$fieldName] ?? $fieldName;
            return $displayName . ': ' . $ruleMessage;
        }
        return $errorMessage;
    }

    /**
     * 获取单个验证后的字段值
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function getValidated(string $key, $default = null)
    {
        if (!$this->isValidated) {
            $this->validate();
        }
        return $this->validatedData[$key] ?? $default;
    }

    /**
     * 检查是否验证通过
     *
     * @return bool
     */
    public function isValid(): bool
    {
        try {
            $this->validate();
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }
} 